EKS オーケストレータを使った SageMaker HyperPod クラスターで S3 をマウントしてみた

EKS オーケストレータを使った SageMaker HyperPod クラスターで S3 をマウントしてみた

Clock Icon2025.01.06

こんにちは!クラウド事業本部コンサルティング部のたかくに(@takakuni_)です。

みなさん SageMaker HyperPod 触っていますでしょうか。

先日、EKS オーケストレータを使った SageMaker HyperPod クラスターで FSx for Lustre をマウントしてみた と言うブログを投稿しました。

https://dev.classmethod.jp/articles/mount-fsx-lustre-on-sagemaker-hyperpod-with-eks-orchestrator/

どうやら、SageMaker HyperPod でも Mountpoint for Amazon S3 CSI ドライバーが使えるようで今回は S3 をマウントしてみようと思います。

For a hands-on experience and guidance on how to set up storage for SageMaker HyperPod cluster orchestrated with Amazon EKS, see the following sections in the Amazon EKS Support in SageMaker HyperPod workshop.
Set up Amazon FSx for Lustre on SageMaker HyperPod
Set up Amazon S3 on SageMaker HyperPod using Mountpoint for Amazon S3

https://docs.aws.amazon.com/sagemaker/latest/dg/sagemaker-hyperpod-eks-setup-storage.html

構成

今回の構成は Mountpoint for Amazon S3 CSI ドライバーを利用して Worker Group に所属する Pod に S3 をマウントしてみます。 FSx for Lustre CSI ドライバーと設定方法の違いを抑えていければと思います。

Untitled(115).png

いつものように HashiCorp Terraform を利用して一連のリソースをデプロイしました。コードは以下に格納されています。

https://github.com/takakuni-classmethod/genai-blog/tree/main/sagemaker_hyperpod_s3_eks

S3 バケット

まずはマウント先となる S3 バケットの作成を行います。命名規則など何か特殊なことはないです。

s3.tf(抜粋)
###################################################
# Data Repository
###################################################
resource "aws_s3_bucket" "data_repository" {
  bucket        = "${local.prefix}-hyperpod-data-${local.account_id}"
  force_destroy = true
}

resource "aws_s3_bucket_public_access_block" "data_repository" {
  bucket                  = aws_s3_bucket.data_repository.bucket
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

resource "aws_s3_bucket_ownership_controls" "data_repository" {
  bucket = aws_s3_bucket.data_repository.bucket
  rule {
    object_ownership = "BucketOwnerPreferred"
  }
}

Mountpoint for Amazon S3 CSI Driver

続いて Mountpoint for Amazon S3 CSI Driver のセットアップです、 FSx for Lustre CSI Driver と同じく IRSA を利用してボリュームのプロビジョニングを行います。

そのため、 OpenID Connect を利用した IAM ロールを作成します。

IAM ロール

注意点が 1 点あり、Service Account の名前は s3-csi-driver-sa です。s3-csi-controller-sa ではありません。

若干、命名規則が異なります。注意しましょう。(私はここで詰まりました。)

s3.tf(抜粋)
###################################################
# Mountpoint for Amazon S3 CSI Driver at AWS
###################################################
data "tls_certificate" "this" {
  url = aws_eks_cluster.this.identity[0].oidc[0].issuer
  depends_on = [
    aws_eks_cluster.this
  ]
}

resource "aws_iam_openid_connect_provider" "this" {
  url = aws_eks_cluster.this.identity[0].oidc[0].issuer

  client_id_list = [
    "sts.amazonaws.com",
  ]

  thumbprint_list = [
    data.tls_certificate.this.certificates[0].sha1_fingerprint
  ]
}

data "aws_iam_policy_document" "assume_csi_driver" {
  statement {
    actions = [
      "sts:AssumeRoleWithWebIdentity",
    ]

    effect = "Allow"

    principals {
      type        = "Federated"
      identifiers = [aws_iam_openid_connect_provider.this.arn]
    }

    condition {
      test     = "StringEquals"
      variable = "${aws_iam_openid_connect_provider.this.url}:aud"
      values = [
        "sts.amazonaws.com",
      ]
    }
    condition {
      test     = "StringEquals"
      variable = "${aws_iam_openid_connect_provider.this.url}:sub"
      values = [
        "system:serviceaccount:kube-system:s3-csi-driver-sa",
      ]
    }
  }
}

IAM ポリシー

S3 のポリシーは以下のドキュメントを参考に作成しました。

https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/s3-csi.html#s3-create-iam-policy

s3.tf(抜粋)
resource "aws_iam_role" "s3_csi_driver" {
  name               = "${local.prefix}-s3-csi-driver-role"
  assume_role_policy = data.aws_iam_policy_document.assume_csi_driver.json
}

data "aws_iam_policy_document" "s3_csi_driver" {
  statement {
    sid = "MountpointFullBucketAccess"
    actions = [
      "s3:ListBucket"
    ]
    effect = "Allow"
    resources = [
      aws_s3_bucket.data_repository.arn,
    ]
  }
  statement {
    sid = "MountpointFullObjectAccess"
    actions = [
      "s3:GetObject",
      "s3:PutObject",
      "s3:AbortMultipartUpload",
      "s3:DeleteObject"
    ]
    effect = "Allow"
    resources = [
      "${aws_s3_bucket.data_repository.arn}/*",
    ]
  }
}

resource "aws_iam_policy" "s3_csi_driver" {
  name        = "${local.prefix}-s3-csi-driver-policy"
  description = "IAM policy for Amazon S3 CSI Driver"
  policy      = data.aws_iam_policy_document.s3_csi_driver.json
}

resource "aws_iam_role_policy_attachment" "s3_csi_driver" {
  role       = aws_iam_role.s3_csi_driver.name
  policy_arn = aws_iam_policy.s3_csi_driver.arn
}

Mountpoint for Amazon S3 CSI Driver Addon

OpenID Connect 経由の IAM ロールの作成が済んだら、Mountpoint for Amazon S3 CSI Driver をインストールします。Mountpoint for Amazon S3 CSI Driver は EKS のアドオンで用意されているためこちらを利用します。

アドオン側で Service Account の IAM ロールを指定できるため、FSx のドライバーでやっていた、アノテーションの処理が自動化されるのは嬉しいですね。

s3.tf(抜粋)
resource "aws_eks_addon" "s3_csi_driver" {
  cluster_name             = aws_eks_cluster.this.name
  addon_name               = "aws-mountpoint-s3-csi-driver"
  addon_version            = "v1.11.0-eksbuild.1"
  service_account_role_arn = aws_iam_role.s3_csi_driver.arn

  depends_on = [
    aws_iam_role_policy_attachment.s3_csi_driver
  ]
}

Persistent Volume

最後に Persistent Volume と Persistent Volume Claim を作成します。

mount_options はこの辺りを参考に作成しました。

https://github.com/awslabs/mountpoint-s3/blob/main/doc/CONFIGURATION.md#file-system-configuration

Persistent Volume のストレージサイズは必須パラメーターのため、ダミーの値を入れているようなイメージです。

s3.tf(抜粋)
###################################################
# Persistent Volume and Persistent Volume Claim
###################################################
resource "kubernetes_persistent_volume_v1" "this" {
  metadata {
    name = "s3-pv"
  }

  spec {
    capacity = {
      storage = "1200Gi" # 設定必須オプションなものの無視される値
    }
    access_modes = ["ReadWriteMany"]
    mount_options = [
      "allow-delete",
      "allow-overwrite",
      "region ${local.region}",
      "prefix training/"
    ]
    persistent_volume_source {
      csi {
        driver        = "s3.csi.aws.com"
        volume_handle = "s3-csi-driver-volume"
        volume_attributes = {
          bucketName = aws_s3_bucket.data_repository.bucket
        }
      }
    }
  }

  depends_on = [
    aws_eks_access_policy_association.this
  ]
}

resource "kubernetes_persistent_volume_claim_v1" "this" {
  metadata {
    name = "s3-claim"
  }
  spec {
    access_modes       = ["ReadWriteMany"]
    storage_class_name = ""
    resources {
      requests = {
        storage = "1200Gi"
      }
    }
  }

  depends_on = [
    aws_eks_access_policy_association.this,
    kubernetes_persistent_volume_v1.this
  ]
}

動作確認

最後に動作確認用の Pod と S3 オブジェクトを作成します。

app.tf
###################################################
# Hello Sample file
###################################################
resource "aws_s3_object" "hello_from_s3" {
  bucket = aws_s3_bucket.data_repository.bucket
  key    = "training/hello_from_s3.txt"

  content = "hello! from S3!"

  depends_on = [
    kubernetes_pod_v1.this
  ]
}

############################################
# Sample Kubernetes Pod
############################################
resource "kubernetes_pod_v1" "this" {
  metadata {
    name = "s3-app"
  }
  spec {
    container {
      name    = "app"
      image   = "amazon/aws-cli"
      command = ["/bin/sh"]
      args    = ["-c", "echo 'Hello from the container!' >> /data/$(date -u).txt; tail -f /dev/null"]
      volume_mount {
        name       = "persistent-storage"
        mount_path = "/data"
      }
    }
    volume {
      name = "persistent-storage"
      persistent_volume_claim {
        claim_name = kubernetes_persistent_volume_claim_v1.this.metadata[0].name
      }
    }
  }

  depends_on = [
    kubernetes_persistent_volume_v1.this,
    awscc_sagemaker_cluster.this,
    aws_eks_addon.s3_csi_driver,
    aws_iam_role_policy_attachment.s3_csi_driver
  ]
}

kubeclt exec で Pod にログインすると、サンプルのファイルが確認できました。

takakuni@ sagemaker_hyperpod_s3_eks % kubectl exec -it s3-app -- /bin/bash
bash-4.2# ls
bash-4.2# cat /data/
Sun Jan  5 09:05:52 UTC 2025.txt  hello_from_s3.txt
bash-4.2# cat /data/hello_from_s3.txt
hello! from S3!bash-4.2#

S3 側も Pod から作成されたファイルが確認できています。

2025-01-05 at 18.09.12-eks-s3-hyperpod-data-120569620949 - S3 バケット  S3  us-west-2.png

まとめ

以上、「EKS オーケストレータを使った SageMaker HyperPod クラスターで S3 をマウントしてみた」でした。大きめなデータセットの読み取りのみ行いたいケースでは活躍しそうな予感がしました。

クラウド事業本部コンサルティング部のたかくに(@takakuni_)でした!

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.